use std::{rc::Rc, cell::RefCell, sync::Arc};

use crate::{native::{self}, rtda::{Frame, heap::{Method, Class}, OperandStack, Object}, instructions::base::{init_class, self}};

pub fn init() {
    native::register("sun/reflect/NativeConstructorAccessorImpl", "newInstance0", "(Ljava/lang/reflect/Constructor;[Ljava/lang/Object;)Ljava/lang/Object;", new_instance0);
}

// private static native Object newInstance0(Constructor<?> c, Object[] os)
// throws InstantiationException, IllegalArgumentException, InvocationTargetException;
// (Ljava/lang/reflect/Constructor;[Ljava/lang/Object;)Ljava/lang/Object;
fn new_instance0(frame: Rc<RefCell<Frame>>) {
    let vars = frame.borrow().get_local_vars();
    let constructor_obj = vars.borrow().get_ref(0).unwrap();
    let arg_arr_obj = vars.borrow().get_ref(1);

    let rs_constructor = get_rs_constructor(constructor_obj);
    let rs_class = rs_constructor.get_class_ptr();
    if !rs_class.init_started() {
        // 获取到此锁可进行初始化。
        let init_lock = rs_class.get_init_lock();
        let _lock = init_lock.lock().unwrap();
        // TODO 231028 不清楚为什么不直接往下执行，而是在执行一次此指令，后续测试。
        // 当前帧的nextPC字段已经指向下一条指令，所以需要修改nextPC，让它重新指向当前指令。
        frame.borrow_mut().revert_next_pc();
        // 再次判断，若在其他线程初始化后获取到锁则跳过初始化
        if !rs_class.init_started() {
            base::init_class(frame.borrow().get_thread(), rs_class);
        }
        return;
    }

    let obj = Box::into_raw(Box::new(Class::new_object(rs_class)));
    let stack = frame.borrow().get_operand_stack();
    stack.borrow_mut().push_ref(Some(obj));

    // call <init>
    let thread = frame.borrow().get_thread();
    let ops = convert_args(obj, arg_arr_obj, rs_constructor.clone());
    let shim_frame = Frame::new_shim_frame(thread.clone(), Rc::new(RefCell::new(ops.unwrap())));
    thread.lock().unwrap().push_frame(shim_frame);

    // init fieldObj
    let shim_frame = thread.lock().unwrap().current_frame();
    base::invoke_method(shim_frame, rs_constructor.clone());


}

fn get_rs_method(method_obj: *mut Object) -> Arc<Method> {
    _get_rs_method(method_obj, false)
}

fn get_rs_constructor(method_obj: *mut Object) -> Arc<Method> {
    _get_rs_method(method_obj, true)
}

fn _get_rs_method(method_obj: *mut Object, is_construcotr: bool) -> Arc<Method> {
    let extra = unsafe { &*method_obj }.get_extra();
    if extra.is_some() {
        return extra.unwrap().get_method()
    }

    if is_construcotr {
        let root = unsafe { &*method_obj }.get_ref_var("root", "Ljava/lang/reflect/Constructor;");
        unsafe { &*root.unwrap() }.get_extra().unwrap().get_method()
    } else {
        let root = unsafe { &*method_obj }.get_ref_var("root", "Ljava/lang/reflect/Method;");
        unsafe { &*root.unwrap() }.get_extra().unwrap().get_method()
    }
}

// Object[] -> []interface{}
fn convert_args(this: *mut Object, arg_arr: Option<*mut Object>, method: Arc<Method>) -> Option<OperandStack> {
    if method.get_arg_slot_count() == 0 {
        return None;
    }

	//	argObjs := argArr.Refs()
	//	argTypes := method.ParsedDescriptor().ParameterTypes()

    let mut ops = OperandStack::new_operand_stack(method.get_arg_slot_count());
    if !method.is_static() {
        ops.push_ref(Some(this));
    }
    if method.get_arg_slot_count() == 1 && !method.is_static() {
        return Some(ops);
    }

	//	for i, argType := range argTypes {
	//		argObj := argObjs[i]
	//
	//		if len(argType) == 1 {
	//			// base type
	//			// todo
	//			unboxed := box.Unbox(argObj, argType)
	//			args[i+j] = unboxed
	//			if argType.isLongOrDouble() {
	//				j++
	//			}
	//		} else {
	//			args[i+j] = argObj
	//		}
	//	}

    Some(ops)
}